package org.realogic.cfm.startup;

import java.io.File;
import java.io.FileFilter;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.ServletContext;

import org.apache.log4j.Logger;
import org.realogic.cfm.KAppContext;
import org.realogic.cfm.KSystemEnvs;
import org.realogic.cfm.plugin.PluginDefinition;
import org.realogic.cfm.plugin.PluginInitializer;
import org.realogic.cfm.plugin.PluginLoader;
import org.realogic.cfm.plugin.PluginSortOrderable;
import org.springframework.context.ApplicationContext;

/**
 * 作用：
 * <p>
 * 1:动态配置ExtDispatcherServlet Context ConfigLocation属性值
 * <p>
 * 2:利用ExtDispatcherServlet初始化机制,载入和初始化应用系统和业务插件
 * 
 */
public final class KSystemStartupLoader {
	private static Logger LOGGER = Logger.getLogger(KSystemStartupLoader.class);

	/**
	 * 系统启动初始化接口
	 */
	private static Map<String, PluginInitializer> initialitions;

	private KSystemStartupLoader() {

	}

	public static final String initBeforeSpring(ServletContext sc) {
		File cfgHomeFile = null;
		if (sc != null) {
			String dhtmxgridPath = sc.getRealPath("/WEB-INF/dhtmxgrid");
			if (dhtmxgridPath == null) {
				throw new IllegalStateException("不能找到dhtmxgrid主目录");
			} else {
				KSystemEnvs.getInstance().setDhtmlxGridPath(dhtmxgridPath);
			}
			
			//系统配置文件所在的目录
			String cfgPath = sc.getRealPath("/WEB-INF/cfgHome");
			if (cfgPath == null) {
				throw new IllegalStateException("不能找到配置主目录");
			} else {
				cfgHomeFile = new File(cfgPath);
			}
			if (!cfgHomeFile.exists() || !cfgHomeFile.isDirectory()) {
				throw new IllegalStateException("配置主目录不存在: " + cfgHomeFile.getAbsolutePath());
			}

		} else {
			cfgHomeFile = KAppContext.getCfgHome();
			if (cfgHomeFile == null) {
				throw new IllegalStateException("不能找到配置主目录.ServletContext is null");
			}
		}
		KAppContext.setContextConfigLocation(cfgHomeFile);
		// Log4J
		// Log4JConfigurator.initialize();
		initContextParam(sc);
		String springConfig = initSpringConfig(cfgHomeFile.getPath());
		return springConfig;
	}

	public static final void initAfterSpring(ServletContext sc, ApplicationContext wac) {
		KAppContext.setApplicationContext(wac);
		initSystemInitializer(wac);
		
		//垃圾回收
		System.gc();
	}

	private static void initContextParam(ServletContext sc) {
		if (sc != null) {
			Enumeration<String> names = sc.getInitParameterNames();
			while (names.hasMoreElements()) {
				String name = (String) names.nextElement();
				String value = sc.getInitParameter(name);
				KSystemEnvs.getInstance().put(name, value);
			}
			String rootPath = sc.getRealPath("");
			KSystemEnvs.getInstance().put(KSystemEnvs.CONFIG_APPLICATION_ROOT_KEY, rootPath);
			System.setProperty(KSystemEnvs.CONFIG_APPLICATION_ROOT_KEY, rootPath);
		}
	}

	private static String initSpringConfig(String theCfgHome) {
		StringBuffer buf = new StringBuffer();
		// 载入主配置文件
		File springHome = new File(theCfgHome, "spring");
		loadSpringInPath(springHome, buf, new XmlFileOnlyFilter("applicationContext"));
		// 载入插件配置信息
		PluginLoader.getInstance().init();
		List<PluginDefinition> defs = PluginLoader.getInstance().getPluginDefinitions();
		XmlFileOnlyFilter tmpPluginFilter = new XmlFileOnlyFilter("spring");
		for (PluginDefinition def : defs) {
			loadSpringInPath(new File(def.getPluginFoler(), "spring"), buf, tmpPluginFilter);
		}
		buf.deleteCharAt(0);
		// System.out.println(buf);
		return buf.toString();
	}

	private static void loadSpringInPath(File springPath, StringBuffer buf, FileFilter filter) {
		if ((springPath.exists()) && (springPath.isDirectory())) {
			String s = null;
			File[] springCfgs = springPath.listFiles(filter);
			for (File springCfg : springCfgs) {
				s = springCfg.getAbsolutePath().replaceAll(" ", "%20");
				buf.append(",file:").append(s);
			}
		}
	}

	private static <T> Map<String, T> getBeansOfSystemInitializer(final Class<T> type, ApplicationContext wac) {
		Map<String, T> result = new LinkedHashMap<String, T>();
		// 增加Spring中配置的SystemInitializer接口实现
		final Map<String, T> initsMap = wac.getBeansOfType(type);
		Comparator<String> comp = new Comparator<String>() {
			public int compare(String o1, String o2) {
				boolean ob1 = false, ob2 = false;
				Object obj1 = initsMap.get(o1);
				Object obj2 = initsMap.get(o2);
				if (obj1 instanceof PluginSortOrderable) {
					ob1 = true;
				}
				if (obj2 instanceof PluginSortOrderable) {
					ob2 = true;
				}
				if (ob1 && !ob2)
					return -1;
				if (ob1 && ob2) {
					PluginSortOrderable s1 = (PluginSortOrderable) obj1;
					PluginSortOrderable s2 = (PluginSortOrderable) obj2;
					if (s1.getSortOrder() < s2.getSortOrder())
						return -1;
				}
				return 1;
			}
		};
		TreeMap<String, T> sortedMap = new TreeMap<String, T>(comp);
		sortedMap.putAll(initsMap);
		result.putAll(sortedMap);
		return result;
	}

	private static void initSystemInitializer(ApplicationContext wac) {
		initialitions = getBeansOfSystemInitializer(PluginInitializer.class, wac);
		Iterator<String> ite = initialitions.keySet().iterator();
		while (ite.hasNext()) {
			String beanName = (String) ite.next();
			PluginInitializer initializer = (PluginInitializer) initialitions.get(beanName);
			long startTime = System.currentTimeMillis();
			initializer.initialize();
			LOGGER.info("Initializer [" + beanName + "] 耗时：" + (System.currentTimeMillis() - startTime) + " MS");
		}
	}

	public static final void destroy(ServletContext sc) {
		Iterator<String> ite = initialitions.keySet().iterator();
		while (ite.hasNext()) {
			String beanName = (String) ite.next();
			PluginInitializer initializer = (PluginInitializer) initialitions.get(beanName);
			try {
				initializer.destroy();
				LOGGER.info("System destroyed [" + beanName + "].");
			} catch (Exception e) {
				LOGGER.error("System destroyed [" + beanName + "].", e);
			}
		}
		System.gc();
	}

	public static void out(String message) {
		System.out.println("**************************************************************************");
		System.out.println("");
		System.out.println("Exception,Error : " + message);
		System.out.println("");
		System.out.println("**************************************************************************");
		try {
			Thread.sleep(5000L);
		} catch (Throwable localThrowable) {
		}
		System.exit(-1);
	}

	private static class XmlFileOnlyFilter implements FileFilter {
		private String prex;

		public XmlFileOnlyFilter(String prex_) {
			prex_ = prex_ == null ? "" : prex_.toLowerCase();
			this.prex = prex_;
		}

		public boolean accept(File f) {
			String s = f.getName().toLowerCase();
			return f.isFile() && s.startsWith(prex) && s.endsWith(".xml");
		}
	}

}
